﻿using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;
using System.Web.UI;
using Wintellect.PowerCollections;
using System.Web.UI.WebControls;
using System.Collections.ObjectModel;
using System.Web.UI.HtmlControls;

namespace SurveyHost.Core.Controls
{
    [ToolboxItem(false)]
    [ValidationProperty("AnswerText")]
    public class RadioButtonsWithTooltips : BaseSurveyQuestion
    {
        private RadioButtonList buttons;
        private LiteralControl literal;
        private Collection<AnswerValueTriple> _answerValueTriples;
        private const string _helpText = @"
<p>This answer type consists of a horizontal list of radio buttons to which you can assign tooltips.  Only one option can be selected per question.</p>
<p>The configuration consists of a series of option/value/tooltip triples.  These triples are delimited by, or separated from each other, by the pipe character ( | ).</p>
<p>The parts of the triple are delimited by a semicolon ( ; ).  The 'option' text is displayed to the participant.  The 'value' is the data recorded when the option is selected.  The tooltip is shown to the user when they hover over the option with the mouse.</p>
<p>An example of a yes/no question's configuration would be:<br/><center>yes;1;I agree|no;2;I do not agree|No answer;0;I refuse to answer</center></p>";

        /// <summary>
        /// Help text that can be displayed to users to instruct them how to generate a configuration string.
        /// </summary>
        /// <value></value>
        /// <remarks>Eventually will be replaced by a custom web control used to generate the configuration string.</remarks>
        public override string ConfigurationHelpText
        {
            get
            {
                return _helpText;
            }
        }

        /// <summary>
        /// The list of answers and corresponding values.
        /// </summary>
        /// <remarks>Each item in the collection is a pair of strings.  
        /// The first string is the answer text to display to the user.  The second string is the </remarks>
        public virtual Collection<AnswerValueTriple> AnswerValueTriples
        {
            get
            {
                if (_answerValueTriples == null)
                    _answerValueTriples = new Collection<AnswerValueTriple>();
                return _answerValueTriples;
            }
        }

        /// <summary>
        /// The response from the user
        /// </summary>
        /// <value></value>
        /// <remarks>Note to extenders:  AnswerText = null indicates the user refused to answer.
        /// </remarks>
        public override string AnswerText
        {
            get
            {
                if (buttons.SelectedIndex == -1 || buttons.SelectedIndex >= AnswerValueTriples.Count)
                    return string.Empty;
                return buttons.SelectedValue;
            }
            set
            {
                buttons.SelectedIndex = -1;
                foreach (ListItem i in buttons.Items)
                    if (i.Text.Equals(value, StringComparison.CurrentCultureIgnoreCase))
                    {
                        i.Selected = true;
                        break;
                    }
            }
        }

        /// <summary>
        /// Called by the base class at the time it is appropriate to parse the configuration string,
        /// The configuration can be stored or used to create controls.
        /// </summary>
        protected override void ParseConfigurationString()
        {
            if (AnswerValueTriples.Count != 0)
                return;

            string[] items;
            foreach (string pair in ConfigurationString.Split('|'))
            {
                items = pair.Split(';');
                if (items.Length != 3)
                    continue;
                AnswerValueTriples.Add(new AnswerValueTriple(items[0], items[1], items[2]));
            }
        }

        /// <summary>
        /// Called by the ASP.NET page framework to notify server controls that use composition-based implementation to create any child controls they contain in preparation for posting back or rendering.
        /// </summary>
        protected override void CreateChildControls()
        {
            base.CreateChildControls();
            ParseConfigurationString();
            HtmlGenericControl questionText = new HtmlGenericControl(HtmlTextWriterTag.Div.ToString());
            HtmlGenericControl questionAnswer = new HtmlGenericControl(HtmlTextWriterTag.Div.ToString());
            questionText.Attributes.Add(HtmlTextWriterAttribute.Class.ToString(), "radioButtonQuestionText");
            questionAnswer.Attributes.Add(HtmlTextWriterAttribute.Class.ToString(), "radioButtonQuestionAnswer");
            Controls.Add(questionAnswer);
            Controls.Add(questionText);

            literal = new LiteralControl
            {
                Text =
                    string.Format(
                    QuestionLineFormat, QuestionIndex, QuestionText)
            };

            questionText.Controls.Add(literal);

            buttons = new RadioButtonList();
            buttons.SelectedIndexChanged += SelectedIndexChanged;

            ListItem li;

            foreach (AnswerValueTriple triple in AnswerValueTriples)
            {
                li = new ListItem(triple.AnswerText, triple.ValueText);
                li.Attributes.Add(HtmlTextWriterAttribute.Title.ToString(), triple.ToolTip);
                buttons.Items.Add(li);
            }

            buttons.RepeatLayout = RepeatLayout.Flow;
            buttons.RepeatDirection = RepeatDirection.Horizontal;
            questionAnswer.Controls.Add(buttons);

            HtmlGenericControl clearDiv = new HtmlGenericControl(HtmlTextWriterTag.Div.ToString());
            clearDiv.Attributes.Add(HtmlTextWriterAttribute.Class.ToString(), "clearDiv");
            Controls.Add(clearDiv);
        }

        /// <summary>
        /// handles the SelectedIndexChanged event
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        protected void SelectedIndexChanged(object sender, EventArgs e)
        {
            OnAnswerGiven(new AnswerEventArgs(QuestionId, AnswerText));
        }
    }

    /// <summary>
    /// Contains the text of an answer and its corresponding value and tooltip.
    /// </summary>
    [Serializable]
    public class AnswerValueTriple
    {
        /// <summary>
        /// Gets or sets the answer text that is displayed to the user.
        /// </summary>
        /// <value>The answer text.</value>
        public string AnswerText
        {
            get;
            set;
        }
        /// <summary>
        /// Gets or sets the value text to return for this answer.
        /// </summary>
        /// <value>The value text.</value>
        public string ValueText
        {
            get;
            set;
        }
        /// <summary>
        /// Gets or sets the tool tip.
        /// </summary>
        /// <value>The tool tip.</value>
        public string ToolTip { get; set; }

        /// <summary>
        /// Initializes a new instance of the <see cref="AnswerValueTriple"/> class.
        /// </summary>
        public AnswerValueTriple() { }

        /// <summary>
        /// Initializes a new instance of the <see cref="AnswerValueTriple"/> class.
        /// </summary>
        /// <param name="answer">The answer.</param>
        /// <param name="value">The value.</param>
        /// <param name="tooltip">The tooltip.</param>
        public AnswerValueTriple(string answer, string value, string tooltip)
        {
            AnswerText = answer;
            ValueText = value;
            ToolTip = tooltip;
        }

        /// <summary>
        /// Determines whether the specified <see cref="T:System.Object"/> is equal to the current <see cref="T:System.Object"/>.
        /// </summary>
        /// <param name="obj">The <see cref="T:System.Object"/> to compare with the current <see cref="T:System.Object"/>.</param>
        /// <returns>
        /// true if the specified <see cref="T:System.Object"/> is equal to the current <see cref="T:System.Object"/>; otherwise, false.
        /// </returns>
        /// <exception cref="T:System.NullReferenceException">The <paramref name="obj"/> parameter is null.</exception>
        public override bool Equals(object obj)
        {

            if (obj == null || GetType() != obj.GetType())
            {
                return false;
            }

            AnswerValueTriple other = obj as AnswerValueTriple;
            if (other.AnswerText.Equals(this.AnswerText, StringComparison.OrdinalIgnoreCase) &&
                other.ValueText.Equals(this.ValueText, StringComparison.OrdinalIgnoreCase) &&
                other.ToolTip.Equals(this.ToolTip, StringComparison.OrdinalIgnoreCase))
                return true;
            return false;
        }

        /// <summary>
        /// Serves as a hash function for a particular type. <see cref="M:System.Object.GetHashCode"></see> is suitable for use in hashing algorithms and data structures like a hash table.
        /// </summary>
        /// <returns>
        /// A hash code for the current <see cref="T:System.Object"></see>.
        /// </returns>
        public override int GetHashCode()
        {
            return AnswerText.GetHashCode() ^ ValueText.GetHashCode() ^ ToolTip.GetHashCode();
        }

    }
}
